#ifndef __LEXER_TYPES_CPP__
#define __LEXER_TYPES_CPP__

#include "utils.cpp"
#include <string>
#include <unordered_map>

using std::string;

enum class TokenStateType;
enum class TokenType;
class GrammarT;
class Token;
struct Position;
// 获取keyword的类型，如果不是keyword，则返回ID
TokenType getKeywordType(string token);
// 获取token字面量
string getTokenLiteral(TokenType token);

enum class TokenStateType{
    START, DONE, ERROR,
    // 接受ID的状态
    ID_LETTER, ID_UNDERLINE, ID_DIGIT,
    // 接受数字的状态
    DIG_ZERO, DIG_DIGIT,
    // 接受string的状态
    STR_CHAR, STR_ESCAPE, 
    // 接受位移运算符的状态
    LT, GT
};


enum class TokenType{
    // 特殊标识
    ENDFILE, ERROR, 
    // 类型关键字
    STRUCT, FLOAT, BOOLEAN, SHORT, LONG, DOUBLE, INT8, INT16, INT32,
    INT64, UINT8, UINT16, UINT32, UINT64, CHAR, UNSIGNED,
    // 运算符
    LBRACE, RBRACE, SEMICOLON, LBRACKET, RBRACKET, TIMES, PLUS, MINUS,
    APPROX, SLASH, PERCENT, RSHIFT, LSHIFT, AND, XOR, OR, COMMA,
    // 其余词法
    ID, INTEGER, STRING, TRUE, FALSE
};

class GrammarT {
public:
    // 是否为终结符
    virtual bool isTerminal() = 0;
};

struct Position{
    int line;
    int col;
};

class Token: GrammarT{
public:
    TokenType tokenType;
    string word;
    Position startPos;
    Position endPos;
    string getName() { return getTokenLiteral(tokenType); }
    bool isTerminal() override { return true; }
    Token() { 
        tokenType = TokenType::ID;
        word = "";
    };
    Token(string word, TokenType token) : word(word), tokenType(token){};
};

static const std::unordered_map<std::string, TokenType> keywordMap = {
    {"struct", TokenType::STRUCT},
    {"float", TokenType::FLOAT},
    {"boolean", TokenType::BOOLEAN},
    {"short", TokenType::SHORT},
    {"long", TokenType::LONG},
    {"double", TokenType::DOUBLE},
    {"int8", TokenType::INT8},
    {"int16", TokenType::INT16},
    {"int32", TokenType::INT32},
    {"int64", TokenType::INT64},
    {"uint8", TokenType::UINT8},
    {"uint16", TokenType::UINT16},
    {"uint32", TokenType::UINT32},
    {"uint64", TokenType::UINT64},
    {"char", TokenType::CHAR},
    {"unsigned", TokenType::UNSIGNED},
    {"true", TokenType::TRUE},
    {"false", TokenType::FALSE}
};



TokenType getKeywordType(string token){
    for (int i = 0; i < token.size(); ++i) {
        token[i] = tolower(token[i]);
    }
    if(keywordMap.count(token))
        return keywordMap.at(token);
    else
        return TokenType::ID;
}

// {};[]*+-/~%&^|,
static const std::unordered_map<char, TokenType> operatorMap={
    {'{', TokenType::LBRACE},
    {'}', TokenType::RBRACE},
    {';', TokenType::SEMICOLON},
    {'[', TokenType::LBRACKET},
    {']', TokenType::RBRACKET},
    {'*', TokenType::TIMES},
    {'+', TokenType::PLUS},
    {'-', TokenType::MINUS},
    {'/', TokenType::SLASH},
    {'~', TokenType::APPROX},
    {'%', TokenType::PERCENT},
    {'&', TokenType::AND},
    {'^', TokenType::XOR},
    {'|', TokenType::OR},
    {',', TokenType::COMMA}
};

TokenType getOperatorType(char ch) { return operatorMap.at(ch); }


static string literalss[] = {
    "$", "Error",
    "Struct", "Float", "Boolean", "Short", "Long", "Double", "Int8", "Int16", "Int32",
    "Int64", "Uint8", "Uint16", "Uint32", "Uint64", "Char", "Unsigned",
    "Lbrace", "Rbrace", "Semicolon", "Lbracket", "Rbracket", "Times", "Plus", "Minus",
    "Approx", "Slash", "Percent", "Rshift", "Lshift", "And", "Xor", "Or", "Comma",
    "ID", "Integer", "String", "True", "False"
};

string getTokenLiteral(TokenType token){
    return literalss[std::underlying_type_t<TokenType>(token)];
}



#endif
